package com.chagee.store.operation.server.service.biz.other;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.chagee.store.operation.common.constant.BatchUpdateSettlementConstant;
import com.chagee.store.operation.server.entity.StoreDO;
import com.chagee.store.operation.server.model.bo.BatchUpdateSettlementBO;
import com.chagee.store.operation.server.model.bo.BatchUpdateSettlementErrBO;
import com.chagee.store.operation.server.service.base.StoreBaseService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : hk
 * @Date : 2024/9/25
 */

@Slf4j
@EqualsAndHashCode(callSuper = true)
@Data
public class BatchUpdatePenalizeListener extends AnalysisEventListener<Map<Integer, String>> {


	private StoreBaseService storeBaseService;

	/**
	 * 用于存储同一批次的数据
	 */
	private List<BatchUpdateSettlementBO> batchCache;

	/**
	 * 校验后成功的数据
	 */
	private List<BatchUpdateSettlementBO> originalList;

	/**
	 * 校验后失败的数据
	 */
	private List<BatchUpdateSettlementErrBO> errBOList;

	/**
	 * 总条数
	 */
	private Long total;

	/**
	 * 数据处理成功条数
	 */
	private Long processSuccessTotal;

	/**
	 * 数据处理失败条数
	 */
	private Long processFailTotal;

	/**
	 * excel 文件头
	 * 字段: index
	 */
	private Map<String, Integer> headMapCache;

	/**
	 * 错误信息map
	 */
	private Map<String, String> errorInfoMapCache;

	public BatchUpdatePenalizeListener(StoreBaseService storeBaseService) {
		this.storeBaseService = storeBaseService;
		this.originalList = new ArrayList<>();
		this.errBOList = new ArrayList<>();
		this.total = 0L;
		this.processSuccessTotal = 0L;
		this.processFailTotal = 0L;
		this.batchCache = new ArrayList<>();
	}

	@Override
	public void invoke(Map<Integer, String> original, AnalysisContext context) {

		BatchUpdateSettlementBO data = buildBO(original, headMapCache);

		// 过滤掉无效数据
		if (!effectivelyData(data)) {
			return;
		}

		total++;
		batchCache.add(data);

		// 达到单批次处理条数
		if (batchCache.size() >= BatchUpdateSettlementConstant.BATCH_SIZE) {
			processBatch();
		}
	}

	/**
	 * 构建bo
	 * @param original 原始数据
	 * @param headMapCache 表头
	 * @return bo
	 */
	private BatchUpdateSettlementBO buildBO(Map<Integer, String> original, Map<String, Integer> headMapCache) {
		BatchUpdateSettlementBO bo = new BatchUpdateSettlementBO();
		// 表头对不上，跳过
		if (!CollectionUtils.isEmpty(headMapCache)) {
			for (Field field : BatchUpdateSettlementBO.class.getDeclaredFields()) {
				String name = field.getName();
				Integer index = headMapCache.get(name);
				// 不存在跳过
				if (Objects.isNull(index)) {
					continue;
				}
				String value = original.get(index);
				// 空值跳过
				if (StringUtils.isNotBlank(value)) {
					try {
						field.setAccessible(true);
						field.set(bo, value);
					} catch (IllegalAccessException e) {
						log.error("BatchUpdatePenalizeListener_buildBO_error {}", name, e);
					}
				}
			}
		}
		return bo;
	}

	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		// batchCache 中可能还存在未处理的数据
		if (!CollectionUtils.isEmpty(batchCache)) {
			processBatch();
		}
		log.info("BatchUpdateCoachesListener_doAfterAllAnalysed_result success {} {} {} {}", total, processSuccessTotal, processFailTotal, JSONUtil.toJsonStr(errBOList));
	}

	@Override
	public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
		Map<String, String> allCodeMap = BatchUpdateSettlementBO.getHeadMap();
		log.info("BatchUpdateCoachesListener_invokeHeadMap_getAllLanguageCodeMap {}", JSONUtil.toJsonStr(allCodeMap));
		headMapCache = new HashMap<>();
		headMap.forEach((index, key) -> {
			String field = allCodeMap.get(key);
			if (StringUtils.isNotBlank(field)) {
				headMapCache.put(field, index);
			}

		});
	}

	/**
	 * 校验是否是有效数据
	 * @param data data
	 * @return bool
	 */
	private static boolean effectivelyData(BatchUpdateSettlementBO data) {
		Field[] fields = data.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Object o = null;
			try {
				o = field.get(data);
			} catch (IllegalAccessException e) {
				log.error("BatchUpdateCoachesListener_effectivelyData_field_get_throw_exception. {}", field.getName(), e);
				continue;
			}
			// 有一列数据为非空即为正常数据
			if (Objects.nonNull(o)) {
				// 过滤代码覆盖率插件添加的一些数据
				if (!(o instanceof String)) {
					log.info("BatchUpdateCoachesListener_effectivelyData_jacoco_value {} {}", field.getName(), o);
					continue;
				}
				// string 类型是空串也不处理
				if (StringUtils.isBlank((String) o)) {
					continue;
				}
				return true;
			}
		}

		return false;
	}

	/**
	 * 处理单批次数据
	 */
	private void processBatch() {
		if (CollectionUtils.isEmpty(batchCache)) {
			return;
		}
		List<String> storeNos = batchCache.stream().map(BatchUpdateSettlementBO::getStoreNo).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());

		List<StoreDO> storeDOS = storeBaseService.queryBaseInfoByStoreNoBatchUpdate(storeNos);
		Map<String, StoreDO> storeMap = storeDOS.stream().collect(Collectors.toMap(StoreDO::getStoreNo, v -> v, (v1, v2) -> v1));

		for (BatchUpdateSettlementBO settlementBO : batchCache) {
			// 获取门店
			StoreDO storeDO = storeMap.get(settlementBO.getStoreNo());

			String errInfo = checkData(settlementBO, storeDO);
			// 存在异常信息
			if (StringUtils.isNotBlank(errInfo)) {
				BatchUpdateSettlementErrBO errBO = new BatchUpdateSettlementErrBO();
				BeanUtil.copyProperties(settlementBO, errBO);
				errBO.setFailMsg(errInfo);
				errBOList.add(errBO);
				processFailTotal++;
				continue;
			}
			// 正常数据
			originalList.add(settlementBO);
			processSuccessTotal++;
		}
		// 清空当前批次cache
		batchCache.clear();
	}

	/**
	 * 校验数据是否正常
	 * @param settlementBO 原数据
	 * @param storeDO 门店数据
	 * @return bool 异常：true 正常：false
	 */
	private String checkData(BatchUpdateSettlementBO settlementBO, StoreDO storeDO) {

		Set<String> errInfo = new HashSet<>();

		// 真实门店不存在
		if (Objects.isNull(storeDO)) {
			errInfo.add(BatchUpdateSettlementConstant.STORE_NOT_EXISTS);
		}

		// 校验门店状态
		if (Objects.nonNull(storeDO)) {
			if (!StringUtils.equals(storeDO.getStoreName(), settlementBO.getStoreName())) {
				errInfo.add(BatchUpdateSettlementConstant.STORE_INFO_ERROR);
			}
			if (storeDO.getClosingTaskStatus().equals(NumberUtils.INTEGER_ZERO)) {
				errInfo.add(BatchUpdateSettlementConstant.STORE_ON_INFO_ERROR);
			}
		}
		if (StringUtils.isNotBlank(settlementBO.getFloorPrice()) && Integer.parseInt(settlementBO.getFloorPrice())<0){
			errInfo.add(BatchUpdateSettlementConstant.FLOOR_PRICE_INFO_ERROR);
		}

		// 无异常信息
		if (CollectionUtils.isEmpty(errInfo)) {
			return null;
		}
		return String.join(BatchUpdateSettlementConstant.UPDATE_COACHES_ERR_DELIMITER, errInfo);
	}
}
